﻿using System;
using System.Configuration;
using System.IO;

namespace Altairis.FluffyCloud.Security {

    public class SignedToken {

        public static string CreateSignedToken(params object[] values) {
            if (values == null) throw new ArgumentNullException("values");
            if (values.Length < 1) throw new ArgumentException("You must supply at least one token value.", "values");

            // Serialize data
            byte[] data;
            using (var ms = new MemoryStream()) {
                using (var bw = new BinaryWriter(ms)) {
                    foreach (var value in values) {
                        if (value.GetType() == typeof(string)) {
                            bw.Write((string)value);
                        }
                        else if (value.GetType() == typeof(long)) {
                            bw.Write((long)value);
                        }
                        else {
                            throw new NotSupportedException("Type not supported");
                        }
                    }
                }
                data = ms.ToArray();
            }

            // Compute hash
            using (var hmac = new System.Security.Cryptography.HMACSHA1()) {
                hmac.Key = GetMacKey();
                var hash = hmac.ComputeHash(data);
                return ToUrlSafeBase64String(hash);
            }
        }

        private static byte[] GetMacKey() {
            var prk = ConfigurationManager.AppSettings["TokenSigningKey"];
            if (string.IsNullOrEmpty(prk)) throw new ConfigurationErrorsException("The TokenSigningKey AppSetting is missing or empty.");
            try {
                return Convert.FromBase64String(prk);
            }
            catch (Exception ex) {
                throw new ConfigurationErrorsException("The TokenSigningKey AppSetting is not valid Base64.", ex);
            }
        }

        private static string ToUrlSafeBase64String(byte[] data) {
            var s = Convert.ToBase64String(data);
            s = s.Replace('+', '-');
            s = s.Replace('/', '_');
            s = s.TrimEnd('=');
            return s;
        }
    }
}